"""
Case Type   : 多块预读
Case Name   : 开启多块预读，多session并发扫描堆表
Create At   : 2024/12/04
Owner       : @li-xin12345
Description :
    1、创建分区表，重启
    2、多session并发扫描堆表
    3、查看日志中打印的预读块数量
    4、清理环境
Expect      :
    1、成功
    2、成功
    3、预读了设置的块数量
    4、成功
History     :
"""
import os
import unittest

from yat.test import Node
from yat.test import macro

from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from testcase.utils.ComThread import ComThread


class SessionTest(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.constant = Constant()
        self.common = Common()
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.pri_user_node = Node('PrimaryDbUser')
        self.tb_name = 't_multi_bulk_read_0013'
        self.pg_log = \
            os.path.join(macro.PG_LOG_PATH, macro.DN_NODE_NAME.split('/')[0])

    def test_multi_bulk_read(self):
        text = '----step1: 建表，重启；expect: 成功----'
        self.log.info(text)
        sql = f'''drop table if exists {self.tb_name} cascade;
        create table {self.tb_name} (
            id serial primary key,
            name varchar(20) not null,
            age tinyint default 0,
            height decimal(4,2),
            gender char(10) default null,
            cls_id int default 0,
            is_delete bit default '0'
        ) partition by range(id) (
            partition part01 values less than (5000),
            partition part02 values less than (10000),
            partition part03 values less than (15000),
            partition part04 values less than (20000),
            partition part05 values less than (maxvalue)
        );
        insert into {self.tb_name}
        values (default, 'name' || generate_series(1,20000), 
        trunc(random()*10 + 15), trunc(random(),2)+1, 
        case when random()>0.3 then 
        case when random()>0.63 then '男' else '女' end else null end, 
        trunc(random()*10), floor(random()*2)::int::bit);
        '''
        res = self.pri_sh.execut_db_sql(sql)
        self.log.info(res)
        self.assertIn(self.constant.DROP_TABLE_SUCCESS, res, f'执行失败：{text}')
        self.assertIn(self.constant.CREATE_TABLE_SUCCESS,
                      res, f'执行失败：{text}')
        self.assertIn('INSERT 0 20000', res, f'执行失败：{text}')

        msg = self.pri_sh.restart_db_cluster()
        self.log.info(msg)
        status = self.pri_sh.get_db_cluster_status()
        self.assertTrue("Degraded" in status or "Normal" in status)

        text = '----step2: 多session并发扫描堆表；expect: 成功----'
        self.log.info(text)
        sql = f"set heap_bulk_read_size = 16;" \
              f"select count(*) from {self.tb_name};"
        threads = [ComThread(self.pri_sh.execut_db_sql,
                             args=(sql,)) for i in range(9)]
        self.log.info(threads)
        for t in threads:
            t.setDaemon(True)
            t.start()

        self.log.info(f'--获取线程结果--')
        for t in threads:
            t.join(60)
            t_res = t.get_result()
            self.log.info(t_res)
            self.assertIn('20000', t_res, f'执行失败：{text}')

        text = '----step3: 查看日志中打印的预读块数量；expect: 预读了设置的块数量----'
        self.log.info(text)
        cmd = f"cd {self.pg_log};" \
              f"ls -t | head -1 | awk '{{{{print $1}}}}' | " \
              f"xargs cat | tail -30 | " \
              f"grep 'End of pre-Read, the max blocks batch is'"
        self.log.info(cmd)
        res = self.common.get_sh_result(self.pri_user_node, cmd)
        self.log.info(res)
        self.assertIsNotNone(res, f'执行失败：{text}')

    def tearDown(self):
        text = '----step4: 清理环境;expect:成功----'
        self.log.info(text)
        sql = f"drop table if exists {self.tb_name} cascade;"
        res = self.pri_sh.execut_db_sql(sql)
        self.log.info(res)
        self.assertIn(self.constant.DROP_TABLE_SUCCESS, res, f'执行失败：{text}')
        self.log.info(f'-----{os.path.basename(__file__)} end-----')